package de.jmda.core.mproc;

import static de.jmda.core.mproc.ProcessingUtilities.asVariableElement;
import static de.jmda.core.mproc.ProcessingUtilities.getTypeElement;
import static de.jmda.core.mproc.ProcessingUtilities.isA;
import static de.jmda.core.mproc.ProcessingUtilities.isProcessingOver;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;

import org.junit.Test;

import de.jmda.core.MarkerAnnotationType;
import de.jmda.core.mproc.Processor;

public class JUTProcessingUtilitiesIsA extends AbstractJUTProcessors
{
	@MarkerAnnotationType private class TestTypeProcessed
	{
		@SuppressWarnings({ "unused", "rawtypes" }) private Collection         collectionRawtypes;
		@SuppressWarnings({ "unused"             }) private Collection<String> collectionStrings;
		@SuppressWarnings({ "unused", "rawtypes" }) private List               listRawtypes;
		@SuppressWarnings({ "unused"             }) private List<String>       listStrings;
		@SuppressWarnings({ "unused", "rawtypes" }) private ArrayList          arrayListRawtypes;
		@SuppressWarnings({ "unused"             }) private ArrayList<String>  arrayListStrings;
	}
	
	@SupportedAnnotationTypes(value = { "de.jmda.core.MarkerAnnotationType" })
	@SupportedSourceVersion(value = SourceVersion.RELEASE_7)
	private class TestProcessor extends Processor
	{
		private TypeElement typeElement_TestTypeProcessed;
		
		private VariableElement variableElement_collectionRawtypes;
		private VariableElement variableElement_collectionStrings;
		private VariableElement variableElement_listRawtypes;
		private VariableElement variableElement_listStrings;
		private VariableElement variableElement_arrayListRawtypes;
		private VariableElement variableElement_arrayListStrings;

		@Override
		protected boolean process()
		{
			if (isProcessingOver() == false)
			{
				typeElement_TestTypeProcessed = getTypeElement(TestTypeProcessed.class);

				for (Element enclosedElement :
				     typeElement_TestTypeProcessed.getEnclosedElements())
				{
					String simpleName = enclosedElement.getSimpleName().toString();

					VariableElement variableElement = asVariableElement(enclosedElement);

					if (variableElement != null)
					{
						if (simpleName.equals("collectionRawtypes"))
						{
							variableElement_collectionRawtypes = variableElement;
						}
						else if (simpleName.equals("collectionStrings"))
						{
							variableElement_collectionStrings = variableElement;
						}
						else if (simpleName.equals("listRawtypes"))
						{
							variableElement_listRawtypes = variableElement;
						}
						else if (simpleName.equals("listStrings"))
						{
							variableElement_listStrings = variableElement;
						}
						else if (simpleName.equals("arrayListRawtypes"))
						{
							variableElement_arrayListRawtypes = variableElement;
						}
						else if (simpleName.equals("arrayListStrings"))
						{
							variableElement_arrayListStrings = variableElement;
						}
						else
						{
							fail(
									"unexpected enclosed element named " + simpleName + ", " +
									"type " + variableElement.asType());
						}
					}
				}
			}

			return false;
		}

		@Override
		protected Set<Class<? extends Annotation>> getSupposedSupportedAnnotationTypes()
		{
			return asSet(MarkerAnnotationType.class);
		}
	}

	private TestProcessor testProcessor = new TestProcessor();

	@Override
	protected List<? extends Processor> getProcessors()
	{
		return asList(testProcessor);
	}

	@Test
	public void collectionRawtypesIsACollectionRawtypes()
	{
		assertTrue(
				isA(
						testProcessor.variableElement_collectionRawtypes.asType(),
						testProcessor.variableElement_collectionRawtypes.asType()));
	}

	@Test
	public void collectionRawtypesIsNotAListRawtypes()
	{
		assertFalse(
				isA(
						testProcessor.variableElement_collectionRawtypes.asType(),
						testProcessor.variableElement_listRawtypes.asType()));
	}

	@Test
	public void collectionRawtypesIsNotAnArrayListRawtypes()
	{
		assertFalse(
				isA(
						testProcessor.variableElement_collectionRawtypes.asType(),
						testProcessor.variableElement_arrayListRawtypes.asType()));
	}

	@Test
	public void collectionRawtypesIsACollectionStrings()
	{
		assertTrue(
				isA(
						testProcessor.variableElement_collectionRawtypes.asType(),
						testProcessor.variableElement_collectionStrings.asType()));
	}

	@Test
	public void collectionRawtypesIsNotAListStrings()
	{
		assertFalse(
				isA(
						testProcessor.variableElement_collectionRawtypes.asType(),
						testProcessor.variableElement_listStrings.asType()));
	}

	@Test
	public void collectionRawtypesIsNotAnArrayListStrings()
	{
		assertFalse(
				isA(
						testProcessor.variableElement_collectionRawtypes.asType(),
						testProcessor.variableElement_arrayListStrings.asType()));
	}

	@Test
	public void listRawtypesIsACollectionRawtypes()
	{
		assertTrue(
				isA(
						testProcessor.variableElement_listRawtypes.asType(),
						testProcessor.variableElement_collectionRawtypes.asType()));
	}

	@Test
	public void listRawtypesIsAListRawtypes()
	{
		assertTrue(
				isA(
						testProcessor.variableElement_listRawtypes.asType(),
						testProcessor.variableElement_listRawtypes.asType()));
	}

	@Test
	public void listRawtypesIsNotAnArrayListRawtypes()
	{
		assertFalse(
				isA(
						testProcessor.variableElement_listRawtypes.asType(),
						testProcessor.variableElement_arrayListRawtypes.asType()));
	}

	@Test
	public void listRawtypesIsACollectionStrings()
	{
		assertTrue(
				isA(
						testProcessor.variableElement_listRawtypes.asType(),
						testProcessor.variableElement_collectionStrings.asType()));
	}

	@Test
	public void listRawtypesIsAListStrings()
	{
		assertTrue(
				isA(
						testProcessor.variableElement_listRawtypes.asType(),
						testProcessor.variableElement_listStrings.asType()));
	}

	@Test
	public void listRawtypesIsNotAnArrayListStrings()
	{
		assertFalse(
				isA(
						testProcessor.variableElement_listRawtypes.asType(),
						testProcessor.variableElement_arrayListStrings.asType()));
	}

	@Test
	public void listStringsIsACollectionRawtypes()
	{
		assertTrue(
				isA(
						testProcessor.variableElement_listStrings.asType(),
						testProcessor.variableElement_collectionRawtypes.asType()));
	}

	@Test
	public void listStringsIsAListRawtypes()
	{
		assertTrue(
				isA(
						testProcessor.variableElement_listStrings.asType(),
						testProcessor.variableElement_listRawtypes.asType()));
	}

	@Test
	public void listStringsIsNotAnArrayListRawtypes()
	{
		assertFalse(
				isA(
						testProcessor.variableElement_listStrings.asType(),
						testProcessor.variableElement_arrayListRawtypes.asType()));
	}

	@Test
	public void listStringsIsACollectionStrings()
	{
		assertTrue(
				isA(
						testProcessor.variableElement_listStrings.asType(),
						testProcessor.variableElement_collectionStrings.asType()));
	}

	@Test
	public void listStringsIsAListStrings()
	{
		assertTrue(
				isA(
						testProcessor.variableElement_listStrings.asType(),
						testProcessor.variableElement_listStrings.asType()));
	}

	@Test
	public void listStringsIsNotAnArrayListStrings()
	{
		assertFalse(
				isA(
						testProcessor.variableElement_listStrings.asType(),
						testProcessor.variableElement_arrayListStrings.asType()));
	}

	@Test
	public void collectionStringIsACollectionRawtypes()
	{
		assertTrue(
				isA(
						testProcessor.variableElement_collectionStrings.asType(),
						testProcessor.variableElement_collectionRawtypes.asType()));
	}

	@Test
	public void collectionStringIsNotAListRawtypes()
	{
		assertFalse(
				isA(
						testProcessor.variableElement_collectionStrings.asType(),
						testProcessor.variableElement_listRawtypes.asType()));
	}

	@Test
	public void collectionStringIsNotAnArrayListRawtypes()
	{
		assertFalse(
				isA(
						testProcessor.variableElement_collectionStrings.asType(),
						testProcessor.variableElement_arrayListRawtypes.asType()));
	}

	@Test
	public void collectionStringIsACollectionStrings()
	{
		assertTrue(
				isA(
						testProcessor.variableElement_collectionStrings.asType(),
						testProcessor.variableElement_collectionStrings.asType()));
	}

	@Test
	public void collectionStringIsNotAListStrings()
	{
		assertFalse(
				isA(
						testProcessor.variableElement_collectionStrings.asType(),
						testProcessor.variableElement_listStrings.asType()));
	}

	@Test
	public void collectionStringIsNotAnArrayListStrings()
	{
		assertFalse(
				isA(
						testProcessor.variableElement_collectionStrings.asType(),
						testProcessor.variableElement_arrayListStrings.asType()));
	}

//	@Test
//	public void isListACollectionRawtypes()
//	{
//		assertTrue(
//				ProcessingUtilities.isA(
//						listRawtypes.asType(),
//						ProcessingUtilities.getTypeElementCollection()));
//	}
//	
//	@Test
//	public void isListOfStringsACollection()
//	{
//		assertTrue(
//				ProcessingUtilities.isA(
//						listOfStrings.asType(),
//						ProcessingUtilities.getTypeElementCollection()));
//	}
//	
//	@Test
//	public void isListOfStringsACollectionOfStrings()
//	{
//		assertTrue(
//				ProcessingUtilities.isA(
//						listOfStrings.asType(),
//						ProcessingUtilities.asTypeElement(collectionOfStrings)));
//	}
//
//	@Test
//	public void isArrayListACollectionRawtypes()
//	{
//		assertTrue(
//				ProcessingUtilities.isA(
//						arrayListRawtypes.asType(),
//						ProcessingUtilities.getTypeElementCollection()));
//	}
//
//	@Test
//	public void isArrayListOfStringsACollectionRawtypes()
//	{
//		assertTrue(
//				ProcessingUtilities.isA(
//						arrayListOfStrings.asType(),
//						ProcessingUtilities.getTypeElementCollection()));
//	}
//	
//	@Test
//	public void isArrayListOfStringsACollectionOfStrings()
//	{
//		assertTrue(
//				ProcessingUtilities.isA(
//						arrayListOfStrings.asType(),
//						ProcessingUtilities.asTypeElement(collectionOfStrings)));
//	}
}